package com.demo.utils;

import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.util.Calendar;
import java.util.Date;

/**
 * 对 jdk 自带的 Calendar 的应用
 * @author gy
 * @date 2022/7/9
 */
public class CalendarUtils {
    private static final Integer resetTime = 1651989758;
    private static final Integer timePeriodNum = 1;
    private static final Integer timePeriodUnit = 40;
    private static final Date currentDate = new Date();

    public static void main(String[] args) throws ParseException {
        Boolean isReset = isResetGoodsNumByRule(resetTime, timePeriodNum, timePeriodUnit, currentDate);
    }

    private static Boolean isResetGoodsNumByRule(Integer resetTime, Integer timePeriodNum, Integer timePeriodUnit,
                                                 Date currentDate) throws ParseException {
        // 1、获取 重置日期 字符串
        String dateByTimeMillis = DateUtils.getDateByTimeMillis(resetTime * 1000L);

        // 2、将 字符串 转换成 日期 Date对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date resetDate = sdf.parse(dateByTimeMillis);

        // 3、将 Date 和 Calendar 关联
        Calendar cal = Calendar.getInstance();
        cal.setTime(resetDate);

        // 4、通过时间周期数量、时间周期单位，获取到 下个自然日、自然周的时间
        if(timePeriodUnit.equals(TIME_PERIOD_UNIT.DAY.getUnit())) {
            cal.add(Calendar.DAY_OF_MONTH, timePeriodNum);
            System.out.println("规则上次重置时间为 "+ sdf.format(resetDate));//2022-07-05
            System.out.println(timePeriodNum+" 天后的 时间为"+sdf.format(cal.getTime()));//2022-07-08
        }else if(timePeriodUnit.equals(TIME_PERIOD_UNIT.WEEK.getUnit())){
            // 需要获取到重置时间 所在周 周一的时间(自然周)
            Date naturalWeekDate = getNaturalWeekDate(resetDate);
            cal.setTime(naturalWeekDate);
            cal.add(Calendar.DAY_OF_MONTH, timePeriodNum * 7);
            System.out.println("规则上次重置时间为 "+ sdf.format(resetDate));//2022-07-05
            System.out.println(timePeriodNum+" 周后的 时间为"+sdf.format(cal.getTime()));//2022-07-25
        }else if(timePeriodUnit.equals(TIME_PERIOD_UNIT.MONTH.getUnit())){
            // 需要获取到重置时间 所在月 1号的时间(自然月)
            Date naturalMonthDate = getNaturalMonthDate(resetDate);
            cal.setTime(naturalMonthDate);
            cal.add(Calendar.MONTH, timePeriodNum);
            System.out.println("规则上次重置时间为 "+ sdf.format(resetDate));//2022-07-05
            System.out.println(timePeriodNum+" 月后的 时间为"+sdf.format(cal.getTime()));//2022-10-01
        }else if (timePeriodUnit.equals(TIME_PERIOD_UNIT.SEASON.getUnit())){
            Date naturalSeasonDate = getNaturalSeasonDate(resetDate);
            cal.setTime(naturalSeasonDate);
            cal.add(Calendar.MONTH, timePeriodNum * 3);
            System.out.println("规则上次重置时间为 "+ sdf.format(resetDate));//
            System.out.println(timePeriodNum+" 季后的 时间为"+sdf.format(cal.getTime()));//2022-10-01
        }

        // 5、得到规则的触发日期
        Date ruleTriggerDate = cal.getTime();
        SimpleDateFormat sdfNew = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String ruleTrigger = sdfNew.format(ruleTriggerDate);

        // 6、当前日期 和 规则触发日期 进行比较，
        // 如果 当前日期 等于或超过 规则触发日期 返回 true 反之 false
        String current = sdfNew.format(currentDate);
        return currentDate.after(ruleTriggerDate);
    }

    /**
     * 获取 重置时间 所在自然周的 第一天（星期一）
     *
     * @return
     */
    public static Date getNaturalWeekDate(Date resetDate) {

        Calendar c = Calendar.getInstance();
        c.setTime(resetDate);
        c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); // Monday 这里设置一周开始时间是星期一
        Date naturalWeekDate = c.getTime();
        return naturalWeekDate;
    }

    /**
     * 获取 重置时间 所在自然月的 第一天（1号）
     *
     * @return
     */
    public static Date getNaturalMonthDate(Date resetDate) {

        Calendar c = Calendar.getInstance();
        c.setTime(resetDate);
        c.set(Calendar.DAY_OF_MONTH, 1); // 这里设置 一个月 开始的时间为 1号
        Date naturalMonthDate = c.getTime();

        return naturalMonthDate;
    }

    /**
     * 获取 重置时间 所在自然季的 第一天（1号）
     * 01.01 、04.01、07.01、10.01
     * @param resetDate 重置日期
     * @return 自然月日期
     */
    public static Date getNaturalSeasonDate(Date resetDate) {
        Calendar c = Calendar.getInstance();
        c.setTime(resetDate);
        int currentMonth = c.get(Calendar.MONTH) + 1;// JANUARY -- 0 国外的一月 用数字 0 标识
        int seasonFirstMonth = getSeasonFirstMonth(currentMonth);
        c.set(Calendar.MONTH, seasonFirstMonth - 1); // 这里设置 当前季度的第一个月 国外的一月 用数字 0 标识
        c.set(Calendar.DAY_OF_MONTH, 1); // 这里设置 一个月 开始的时间为 1号
        Date naturalSeasonDate = c.getTime();
        return naturalSeasonDate;
    }

    // 获取季度的第一个月
    // 季度一年四季， 第一季度：1月-3月， 第二季度：4月-6月， 第三季度：7月-9月， 第四季度：10月-12月
    private static int getSeasonFirstMonth(int month) {
        int[] months = { 1, 4, 7, 10 };
        if (month >= 1 && month <= 3) {
            return months[0];
        }
        else if (month >= 4 && month <= 6) {
            return months[1];
        }
        else if (month >= 7 && month <= 9) {
            return months[2];
        }
        else {
            return months[3];
        }
    }

    private enum TIME_PERIOD_UNIT {
        /**
         * 天
         */
        DAY(10),
        /**
         * 周
         */
        WEEK(20),
        /**
         * 月
         */
        MONTH(30),
        /**
         * 季
         */
        SEASON(40);

        private final Integer UNIT;

        TIME_PERIOD_UNIT(Integer UNIT){
            this.UNIT = UNIT;
        }

        public Integer getUnit() {
            return UNIT;
        }
    }

    /**
     * 获取一周前的日期
     */
    @Test
    public void m1(){
        long startTime = System.currentTimeMillis();

        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        Date naturalMonthDate = c.getTime();

        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }

    @Test
    public void m2(){
        long startTime = System.currentTimeMillis();

        // 当前时间
        LocalDateTime localDateTime = LocalDateTime.now();
        // 获取当前周几的int类型表示
        int dayOfWeek = localDateTime.getDayOfWeek().get(ChronoField.DAY_OF_WEEK);

        // 减去一周加上 （7 - 当前周周几）
        LocalDateTime localDateTime1 = localDateTime.minusWeeks(1).plusDays(7 - dayOfWeek);
        // 以yyyy-MM-dd输出
        System.out.println(localDateTime1.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");

        System.out.println(getLastWeekDate());
    }


    /**
     * 获取上周日期
     * @return
     */
    private String getLastWeekDate(){
        // 当前时间
        LocalDateTime localDateTime = LocalDateTime.now();
        // 获取当前周几的int类型表示
        int dayOfWeek = localDateTime.getDayOfWeek().get(ChronoField.DAY_OF_WEEK);
        // 减去一周加上 （7 - 当前周周几）
        LocalDateTime localDateTime1 = localDateTime.minusWeeks(1).plusDays(7 - dayOfWeek);
        // 以yyyy-MM-dd输出
        return localDateTime1.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

}


